import {DeviceTabs} from '@site/src/react-luma';

# External WebGL Contexts

This tutorial will be a simple demonstration of how to use an externally created WebGL context 
with luma.gl's higher-level APIs. 

:::caution
The tutorial pages have not yet been updated for luma.gl v9. 
- External context example is temporarily disabled until support is added to luma.gl v9
- This page applies to WebGL only
:::


So far, we have either created a WebGL context ourselves 
to use with low-level APIs, or allowed the the `AnimationLoop` class to create a WebGL context for us. 
luma.gl's higher-level APIs expect some instrumentation on the WebGL context, 
so we can't just use a context we create ourselves with classes like `Model` and `Buffer`. 

The `AnimationLoop` class performs this instrumentation for us using the `instrumentGLContext` 
function from **@luma.gl/gltools**, and we can use this function directly 
if we want to control creation of the context or use a context passed to us by another framework 
(e.g. the GeoSpatial example uses this technique with a WebGL context 
created by [MapboxGL](https://docs.mapbox.com/mapbox-gl-js/api/)).

We'll create a modified version of the [Hello Triangle](/docs/tutorials/hello-triangle) tutorial that creates a WebGL context manually rather than using the `AnimationLoop` class. To start with, we'll modify our imports:

```typescript
import {Model} from '@luma.gl/engine';
import {Buffer, clear} from '@luma.gl/webgl';
import {instrumentGLContext} from '@luma.gl/gltools';
```

We then create our context and pass it to `instrumentGLContext`:

```typescript
const canvas = document.createElement('canvas');
canvas.width = 800;
canvas.height = 600;
document.body.appendChild(canvas);

const gl = instrumentGLContext(canvas.getContext('webgl'));
```

This performs some polyfilling (done by `polyfillContext`, and we create our own render loop using `requestAnimationFrame` rather than using the `AnimationLoop` callbacks.

```typescript
const gl = instrumentGLContext(canvas.getContext('webgl'));
gl.clearColor(0, 0, 0, 1);

const positionBuffer = new Buffer(gl, new Float32Array([-0.5, -0.5, 0.5, -0.5, 0.0, 0.5]));

const colorBuffer = new Buffer(gl, new Float32Array([1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]));

// ...

const model = new Model(gl, {
  vs,
  fs,
  attributes: {
    position: positionBuffer,
    color: colorBuffer
  },
  vertexCount: 3
});

requestAnimationFrame(function draw() {
  requestAnimationFrame(draw);

  clear(gl, {color: [0, 0, 0, 1]});
  model.draw();
});
```

If all went well, a tri-color triangle should render as it did in the **Hello Triangle** example. The full source code is listed below for reference:

```typescript
import {Model} from '@luma.gl/engine';
import {Buffer, clear} from '@luma.gl/webgl';
import {instrumentGLContext} from '@luma.gl/gltools';

const canvas = document.createElement('canvas');
canvas.width = 800;
canvas.height = 600;
document.body.appendChild(canvas);

const gl = instrumentGLContext(canvas.getContext('webgl'));
gl.clearColor(0, 0, 0, 1);

const positionBuffer = new Buffer(gl, new Float32Array([-0.5, -0.5, 0.5, -0.5, 0.0, 0.5]));

const colorBuffer = new Buffer(gl, new Float32Array([1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]));

const vs = `
 attribute vec2 position;
 attribute vec3 color;

 out vec3 vColor;

 void main() {
   vColor = color;
   gl_Position = vec4(position, 0.0, 1.0);
 }
`;

const fs = `
 in vec3 vColor;

 void main() {
   gl_FragColor = vec4(vColor, 1.0);
 }
`;

const model = new Model(gl, {
  vs,
  fs,
  attributes: {
    position: positionBuffer,
    color: colorBuffer
  },
  vertexCount: 3
});

requestAnimationFrame(function draw() {
  requestAnimationFrame(draw);

  clear(gl, {color: [0, 0, 0, 1]});
  model.draw();
});
```
